<!--
 * @Author: fanny.wang
 * @Date: 2019-07-23 11:08:06
 * @LastEditors: fanny.wang
 * @LastEditTime: 2019-07-30 17:58:09
 * @Description: file content
 -->

<template>
  <div class="tetris" ref="tetris">
    <div class="main" ref="main">
      <div class=title><span class="game-name">俄罗斯方块</span><span class="game-score">分数&nbsp;{{score}}</span></div>
      <canvas id="tetris-wrapper" ref="tetris-wrapper" width="390" height="660">
        该浏览器不支持canvas标签
      </canvas>
      <div class="gameover-wraaper" v-show="gameover">
        <div class="gameover"><span>Game Over</span></div>
      </div>
    </div>
    <div class="operate">
      <div class="operate-btn operate-btn--bk1" @click="startGame"><span>{{ inGame ? '重新开始' : '开始游戏' }}</span></div>
      <div class="operate-btn operate-btn--bk1" @click="toggleGame"><span>{{ paused ? '继续游戏' : '暂停游戏' }}</span></div>
      <div class="move">
        <span @click="moveLeft">⇦</span>
        <span @click="moveDown">⇩</span>
        <span @click="moveRight">⇨</span>
      </div>
      <div class="operate-btn operate-btn--bk2" @click="changeBlock"><span>空格键</span></div>
      <div class="tip">
        <span style="font-weight:bold">键盘控制：</span><br>
        <span>➤空格键 → 变换方块</span><br>
        <span>➤⇦ → 左移</span><br>
        <span>➤⇨ → 右移</span><br>
        <span>➤⇩ → 下移</span>
      </div>
    </div>
    <img alt="绿" ref="pattern0" src="../assets/grid1.png" width="30" height="30" style="display: none">
    <img alt="红" ref="pattern1" src="../assets/grid2.png" width="30" height="30" style="display: none">
    <img alt="紫" ref="pattern2" src="../assets/grid3.png" width="30" height="30" style="display: none">
    <img alt="黄" ref="pattern3" src="../assets/grid4.png" width="30" height="30" style="display: none">
    <img alt="蓝" ref="pattern4" src="../assets/grid5.png" width="30" height="30" style="display: none">
  </div>
</template>

<script>
import '../assets/style.css'

export default {
  name: 'Home',
  data () {
    return {
      context: null,
      gridWidth: 30,
      canvasWidth: 390, // 画布宽
      canvasHeight: 660, // 画布高
      gridCoords: [], // 全部坐标
      gridFlags: [], // 全部坐标填充标志
      timer: null,
      inGame: false, // 游戏中
      paused: false, // 暂停游戏
      gameover: false,
      moveSpeed: 300,
      blocksCoord: [],
      blockType: '0', // 方块类型, 形状： 0-....  1-:: 2-.:. 3-'--， 4-,--' 5-:.. 6-..:
      blockTypeNum: 7,
      currentState: '0', // 方块当前状态
      patternNum: 5, // 格子种类
      score: 0
    }
  },
  computed: {
    xLen () {
      return this.canvasWidth / this.gridWidth
    },
    yLen () {
      return this.canvasHeight / this.gridWidth
    }
  },
  mounted () {
    const canvas = this.$refs['tetris-wrapper']
    this.context = canvas.getContext('2d')

    let pad = (document.body.clientHeight - 747) / 2
    pad > 20 && (this.$refs['tetris'].style = `padding-top: ${pad}px`)

    window.onresize = () => {
      let pad = (document.body.clientHeight - 747) / 2
      pad > 20 && (this.$refs['tetris'].style = `padding-top: ${pad}px`)
      pad <= 20 && (this.$refs['tetris'].style = `padding-top: 20px`)
      console.log(pad)
    }

    document.onkeydown = (e) => {
      let key = e.keyCode
      if (this.inGame && !this.paused) {
        if (key === 32) { // 空格
          this.changeBlock()
        }
        if (key === 37) { // ArrowLeft
          this.moveLeft()
        }
        if (key === 39) { // ArrowRight
          this.moveRight()
        }
        if (key === 40) { // ArrowDown
          this.moveDown()
        }
      }
    }
  },
  methods: {
    startGame () {
      this.inGame = true
      this.paused = false
      this.gameover = false
      this.score = 0
      clearInterval(this.timer)
      this.clearRect()
      this.setGridCoordsFlags()
      this.setBlock()
    },
    toggleGame () {
      this.paused = !this.paused
      if (this.paused) { // true 暂停游戏
        clearInterval(this.timer)
      } else { // false 继续游戏
        this.timer = setInterval(this.move, this.moveSpeed)
      }
    },
    setGridCoordsFlags () { // 初始化格子标记
      this.gridCoords = []
      this.gridFlags = []
      for (let x = 0; x < this.xLen; x++) {
        for (let y = 0; y < this.yLen; y++) {
          this.gridCoords.push({ x, y })
          this.gridFlags[`fill_${x}_${y}`] = false
          this.gridFlags[`pattern_${x}_${y}`] = ''
        }
      }
    },
    initBlocksCoord () { // 初始化方块坐标
      this.currentState = '0'
      this.blockType = parseInt(Math.random() * this.blockTypeNum) // 设置方块类型

      const xLenM = parseInt(this.xLen / 2)
      switch (this.blockType) {
        case 0:
          this.blocksCoord = [
            { x: xLenM - 1, y: -1 },
            { x: xLenM, y: -1 },
            { x: xLenM + 1, y: -1 },
            { x: xLenM + 2, y: -1 }
          ]
          break
        case 1:
          this.blocksCoord = [
            { x: xLenM, y: -1 },
            { x: xLenM + 1, y: -1 },
            { x: xLenM, y: 0 },
            { x: xLenM + 1, y: 0 }
          ]
          break
        case 2:
          this.blocksCoord = [
            { x: xLenM, y: -1 },
            { x: xLenM - 1, y: 0 },
            { x: xLenM, y: 0 },
            { x: xLenM + 1, y: 0 }
          ]
          break
        case 3:
          this.blocksCoord = [
            { x: xLenM, y: -1 },
            { x: xLenM, y: 0 },
            { x: xLenM + 1, y: 0 },
            { x: xLenM + 1, y: 1 }
          ]
          break
        case 4:
          this.blocksCoord = [
            { x: xLenM + 1, y: -1 },
            { x: xLenM, y: 0 },
            { x: xLenM + 1, y: 0 },
            { x: xLenM, y: 1 }
          ]
          break
        case 5:
          this.blocksCoord = [
            { x: xLenM - 1, y: -1 },
            { x: xLenM - 1, y: 0 },
            { x: xLenM, y: 0 },
            { x: xLenM + 1, y: 0 }
          ]
          break
        case 6:
          this.blocksCoord = [
            { x: xLenM + 1, y: -1 },
            { x: xLenM - 1, y: 0 },
            { x: xLenM, y: 0 },
            { x: xLenM + 1, y: 0 }
          ]
          break
        default:
          break
      }

      let pattern = `pattern${parseInt(Math.random() * this.patternNum)}` // 设置格子图片
      this.blocksCoord.forEach(coord => {
        coord.pattern = pattern
      })
    },
    moveLeft () { // 左移
      let leftCoord = JSON.parse(JSON.stringify(this.blocksCoord))
      leftCoord.forEach((coord) => {
        coord.x -= 1
      })
      if (this.blocksCoord.findIndex(coord => coord.x === 0) === -1 &&
      leftCoord.findIndex(coord => this.gridFlags[`fill_${coord.x}_${coord.y}`]) === -1) { // 没有任何一个格子坐标 x = 0 && 左移后的位置，没有任何一个格子被标识
        this.clearBlock()
        this.blocksCoord = leftCoord
        this.drawBlock()
      }
    },
    moveRight () { // 右移
      let rightCoord = JSON.parse(JSON.stringify(this.blocksCoord))
      rightCoord.forEach((coord) => {
        coord.x += 1
      })
      if (this.blocksCoord.findIndex(coord => coord.x === this.xLen - 1) === -1 &&
      rightCoord.findIndex(coord => this.gridFlags[`fill_${coord.x}_${coord.y}`]) === -1) { // 没有任何一个格子坐标 x = this.xLen-1 && 右移后的位置，没有任何一个格子被标识
        this.clearBlock()
        this.blocksCoord = rightCoord
        this.drawBlock()
      }
    },
    moveDown () { // 下移
      let isStopped = this.isStopped()
      if (!isStopped) { // 不停止
        this.clearBlock()
        this.blocksCoord.forEach((coord) => {
          coord.y += 1
        })
        this.drawBlock()
      }
    },
    changeBlock () { // 改变方块
      if (this.blockType === 1) { // 形状： 1-::
        return
      }

      let nextState = this.getNextBlockState()
      let nextCoord = this.getNextBlocksCoord(nextState)

      let isChanged = true
      for (let coord of nextCoord) {
        if (this.gridFlags[`fill_${coord.x}_${coord.y}`] || coord.x > this.xLen - 1 || coord.x < 0 || coord.y > this.yLen - 1 || coord.y < 0) {
          isChanged = false
          return true
        }
      }
      if (!isChanged) {
        return
      }
      this.clearBlock()
      this.currentState = nextState // 改变方块状态
      this.blocksCoord = nextCoord // 改变方块坐标数组
      this.drawBlock()
    },
    getNextBlocksCoord (nextState) { // 根据类型、当前状态、下一个状态，获取next方块坐标数组
      let coord = []
      let tempCoord = {}
      switch (this.blockType) {
        case 0:
          if (this.currentState === '0' && nextState === '1') { // 0 to 1
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[0])) // 相对坐标
            coord[0] = { x: tempCoord.x + 1, y: tempCoord.y - 1 }
            coord[1] = { x: tempCoord.x + 1, y: tempCoord.y }
            coord[2] = { x: tempCoord.x + 1, y: tempCoord.y + 1 }
            coord[3] = { x: tempCoord.x + 1, y: tempCoord.y + 2 }
          }
          if (this.currentState === '1' && nextState === '0') { // 1 to 0
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[1])) // 相对坐标
            coord[0] = { x: tempCoord.x - 1, y: tempCoord.y }
            coord[1] = { x: tempCoord.x, y: tempCoord.y }
            coord[2] = { x: tempCoord.x + 1, y: tempCoord.y }
            coord[3] = { x: tempCoord.x + 2, y: tempCoord.y }
          }
          break
        case 2:
          if (this.currentState === '0' && nextState === '1') { // 0 to 1
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[2])) // 相对坐标
            coord[0] = { x: tempCoord.x, y: tempCoord.y - 1 }
            coord[1] = { x: tempCoord.x, y: tempCoord.y }
            coord[2] = { x: tempCoord.x + 1, y: tempCoord.y }
            coord[3] = { x: tempCoord.x, y: tempCoord.y + 1 }
          }
          if (this.currentState === '1' && nextState === '2') { // 1 to 2
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[1])) // 相对坐标
            coord[0] = { x: tempCoord.x - 1, y: tempCoord.y }
            coord[1] = { x: tempCoord.x, y: tempCoord.y }
            coord[2] = { x: tempCoord.x + 1, y: tempCoord.y }
            coord[3] = { x: tempCoord.x, y: tempCoord.y + 1 }
          }
          if (this.currentState === '2' && nextState === '3') { // 2 to 3
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[1])) // 相对坐标
            coord[0] = { x: tempCoord.x, y: tempCoord.y - 1 }
            coord[1] = { x: tempCoord.x - 1, y: tempCoord.y }
            coord[2] = { x: tempCoord.x, y: tempCoord.y }
            coord[3] = { x: tempCoord.x, y: tempCoord.y + 1 }
          }
          if (this.currentState === '3' && nextState === '0') { // 3 to 0
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[2])) // 相对坐标
            coord[0] = { x: tempCoord.x, y: tempCoord.y - 1 }
            coord[1] = { x: tempCoord.x - 1, y: tempCoord.y }
            coord[2] = { x: tempCoord.x, y: tempCoord.y }
            coord[3] = { x: tempCoord.x + 1, y: tempCoord.y }
          }
          break
        case 3:
          if (this.currentState === '0' && nextState === '1') { // 0 to 1
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[1])) // 相对坐标
            coord[0] = { x: tempCoord.x, y: tempCoord.y }
            coord[1] = { x: tempCoord.x + 1, y: tempCoord.y }
            coord[2] = { x: tempCoord.x - 1, y: tempCoord.y + 1 }
            coord[3] = { x: tempCoord.x, y: tempCoord.y + 1 }
          }
          if (this.currentState === '1' && nextState === '0') { // 1 to 0
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[1])) // 相对坐标
            coord[0] = { x: tempCoord.x - 1, y: tempCoord.y - 1 }
            coord[1] = { x: tempCoord.x - 1, y: tempCoord.y }
            coord[2] = { x: tempCoord.x, y: tempCoord.y }
            coord[3] = { x: tempCoord.x, y: tempCoord.y + 1 }
          }
          break
        case 4:
          if (this.currentState === '0' && nextState === '1') { // 0 to 1
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[1])) // 相对坐标
            coord[0] = { x: tempCoord.x - 1, y: tempCoord.y }
            coord[1] = { x: tempCoord.x, y: tempCoord.y }
            coord[2] = { x: tempCoord.x, y: tempCoord.y + 1 }
            coord[3] = { x: tempCoord.x + 1, y: tempCoord.y + 1 }
          }
          if (this.currentState === '1' && nextState === '0') { // 1 to 0
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[1])) // 相对坐标
            coord[0] = { x: tempCoord.x + 1, y: tempCoord.y - 1 }
            coord[1] = { x: tempCoord.x, y: tempCoord.y }
            coord[2] = { x: tempCoord.x + 1, y: tempCoord.y }
            coord[3] = { x: tempCoord.x, y: tempCoord.y + 1 }
          }
          break
        case 5:
          if (this.currentState === '0' && nextState === '1') { // 0 to 1
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[2])) // 相对坐标
            coord[0] = { x: tempCoord.x, y: tempCoord.y - 1 }
            coord[1] = { x: tempCoord.x + 1, y: tempCoord.y - 1 }
            coord[2] = { x: tempCoord.x, y: tempCoord.y }
            coord[3] = { x: tempCoord.x, y: tempCoord.y + 1 }
          }
          if (this.currentState === '1' && nextState === '2') { // 1 to 2
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[2])) // 相对坐标
            coord[0] = { x: tempCoord.x - 1, y: tempCoord.y }
            coord[1] = { x: tempCoord.x, y: tempCoord.y }
            coord[2] = { x: tempCoord.x + 1, y: tempCoord.y }
            coord[3] = { x: tempCoord.x + 1, y: tempCoord.y + 1 }
          }
          if (this.currentState === '2' && nextState === '3') { // 2 to 3
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[1])) // 相对坐标
            coord[0] = { x: tempCoord.x, y: tempCoord.y - 1 }
            coord[1] = { x: tempCoord.x, y: tempCoord.y }
            coord[2] = { x: tempCoord.x - 1, y: tempCoord.y + 1 }
            coord[3] = { x: tempCoord.x, y: tempCoord.y + 1 }
          }
          if (this.currentState === '3' && nextState === '0') { // 3 to 0
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[1])) // 相对坐标
            coord[0] = { x: tempCoord.x - 1, y: tempCoord.y - 1 }
            coord[1] = { x: tempCoord.x - 1, y: tempCoord.y }
            coord[2] = { x: tempCoord.x, y: tempCoord.y }
            coord[3] = { x: tempCoord.x + 1, y: tempCoord.y }
          }
          break
        case 6:
          if (this.currentState === '0' && nextState === '1') { // 0 to 1
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[2])) // 相对坐标
            coord[0] = { x: tempCoord.x, y: tempCoord.y - 1 }
            coord[1] = { x: tempCoord.x, y: tempCoord.y }
            coord[2] = { x: tempCoord.x, y: tempCoord.y + 1 }
            coord[3] = { x: tempCoord.x + 1, y: tempCoord.y + 1 }
          }
          if (this.currentState === '1' && nextState === '2') { // 1 to 2
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[1])) // 相对坐标
            coord[0] = { x: tempCoord.x - 1, y: tempCoord.y }
            coord[1] = { x: tempCoord.x, y: tempCoord.y }
            coord[2] = { x: tempCoord.x + 1, y: tempCoord.y }
            coord[3] = { x: tempCoord.x - 1, y: tempCoord.y + 1 }
          }
          if (this.currentState === '2' && nextState === '3') { // 2 to 3
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[1])) // 相对坐标
            coord[0] = { x: tempCoord.x - 1, y: tempCoord.y - 1 }
            coord[1] = { x: tempCoord.x, y: tempCoord.y - 1 }
            coord[2] = { x: tempCoord.x, y: tempCoord.y }
            coord[3] = { x: tempCoord.x, y: tempCoord.y + 1 }
          }
          if (this.currentState === '3' && nextState === '0') { // 3 to 0
            tempCoord = JSON.parse(JSON.stringify(this.blocksCoord[2])) // 相对坐标
            coord[0] = { x: tempCoord.x + 1, y: tempCoord.y - 1 }
            coord[1] = { x: tempCoord.x - 1, y: tempCoord.y }
            coord[2] = { x: tempCoord.x, y: tempCoord.y }
            coord[3] = { x: tempCoord.x + 1, y: tempCoord.y }
          }
          break
        default:
          break
      }
      coord = coord.map(item => { return { ...item, pattern: tempCoord.pattern } })
      return coord
    },
    getNextBlockState () { // 根据类型和当前状态， 获取next方块状态
      let state = ''
      switch (this.blockType) {
        case 0:
        case 3:
        case 4:
          state =
            this.currentState === '0' ? '1'
              : '0'
          break
        case 2:
        case 5:
        case 6:
          state =
            this.currentState === '0' ? '1'
              : this.currentState === '1' ? '2'
                : this.currentState === '2' ? '3'
                  : '0'
          break
        default:
          break
      }
      return state
    },
    setBlock () { // 设置方块
      this.initBlocksCoord()
      this.timer = setInterval(this.move, this.moveSpeed)
    },
    isStopped () { // 方块是否停止
      for (let coord of this.blocksCoord) {
        // 下一步只要有>=1个格子已被填充，就需要停止  || 方块已到达底部
        if (this.gridFlags[`fill_${coord.x}_${coord.y + 1}`] || coord.y >= this.yLen - 1) {
          return true
        }
      }
      return false
    },
    move () {
      let isStopped = this.isStopped()
      if (!isStopped) { // 不停止
        this.clearBlock()
        // 坐标 y + 1
        this.blocksCoord.forEach((coord) => {
          coord.y += 1
        })
        this.drawBlock()
      } else { // 停止
        clearInterval(this.timer)
        this.flagGrid()
        this.clearLines()
        this.gameOver()
        this.inGame && this.setBlock()
      }
    },
    gameOver () { // 判断游戏结束
      for (let x = 0; x < this.xLen; x++) {
        if (this.gridFlags[`fill_${x}_0`]) {
          this.inGame = false
          this.gameover = true
        }
      }
      !this.inGame && this.drawBlock()
    },
    drawBlock () { // 重绘方块
      this.blocksCoord.forEach((coord) => {
        this.drawGrid(coord)
      })
    },
    clearBlock () { // 清除当前方块坐标
      this.blocksCoord.forEach((coord) => {
        this.clearGrid(coord)
      })
    },
    flagGrid () { // 标记格子
      this.blocksCoord.forEach((coord) => {
        this.gridFlags[`fill_${coord.x}_${coord.y}`] = true
        this.gridFlags[`pattern_${coord.x}_${coord.y}`] = coord.pattern
      })
    },
    drawGrid (coord) {
      this.context.drawImage(this.$refs[`${coord.pattern}`], coord.x * this.gridWidth, coord.y * this.gridWidth, this.gridWidth, this.gridWidth)
    },
    clearGrid (coord) {
      this.context.clearRect(coord.x * this.gridWidth, coord.y * this.gridWidth, this.gridWidth, this.gridWidth)
    },
    clearLines () {
      let unClears = []
      let clears = []
      for (let y = 0; y < this.yLen; y++) {
        for (let x = 0; x < this.xLen; x++) {
          if (!this.gridFlags[`fill_${x}_${y}`]) {
            unClears.push(y)
            break
          }
        }
      }
      // 清除行
      for (let y = 0; y < this.yLen; y++) {
        if (!unClears.includes(y)) {
          clears.push(y)
          this.score++
          for (let x = 0; x < this.xLen; x++) {
            this.gridFlags[`fill_${x}_${y}`] = false
            this.gridFlags[`pattern_${x}_${y}`] = ''
          }
        }
      }
      // 重绘下移
      for (let i = 0; i < clears.length; i++) {
        for (let y = clears[i]; y > 0; y--) {
          for (let x = 0; x < this.xLen; x++) {
            this.gridFlags[`fill_${x}_${y}`] = this.gridFlags[`fill_${x}_${y - 1}`]
            this.gridFlags[`pattern_${x}_${y}`] = this.gridFlags[`pattern_${x}_${y - 1}`]
          }
        }
      }
      if (clears.length > 0) {
        this.clearRect()
        this.gridCoords.forEach(coord => {
          if (this.gridFlags[`fill_${coord.x}_${coord.y}`]) {
            coord.pattern = this.gridFlags[`pattern_${coord.x}_${coord.y}`]
            this.drawGrid(coord)
          }
        })
      }
    },
    clearRect () { // 清除游戏画布
      this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
